var rec = null;

function Recorder() {
    this.leftchannel = [];
    this.recorder = null;
    this.recording = false;
    this.recordingLength = 0;
    this.volume = null;
    this.audioInput = null;
    this.sampleRate = 44100;
    this.audioContext = null;
    this.context = null;
    this.outputString;
    this.lastCharacter = "X";

    rec = this;

    if (!navigator.getUserMedia)
	navigator.getUserMedia = navigator.getUserMedia
		|| navigator.webkitGetUserMedia || navigator.mozGetUserMedia
		|| navigator.msGetUserMedia;

    if (navigator.getUserMedia) {
	navigator.getUserMedia({
	    audio : true
	}, this.init, function(e) {
	    throw "Błąd konwersji dźwięku do pliku.";
	});
    } else
	throw "Przeglądarka nie wspiera obsługi mikrofonu.";

}

Recorder.prototype.startRecording = function() {
    if (!this.recording) {
	console.log("Recording starts");
	this.recording = true;
	this.leftchannel.length = 0;
	this.recordingLength = 0;
    }
}

Recorder.prototype.stopRecording = function() {

    $("#output").html('');

    var threshold = 0.05;

    console.log("Recording ends")
    this.recording = false;

    var leftBuffer = this.mergeBuffers(this.leftchannel, this.recordingLength);

    var interleaved = this.interleave(leftBuffer);

    var buffer = new ArrayBuffer(44 + interleaved.length * 2);
    var view = new DataView(buffer);

    this.writeUTFBytes(view, 0, 'RIFF');
    view.setUint32(4, 44 + interleaved.length * 2, true);
    this.writeUTFBytes(view, 8, 'WAVE');

    this.writeUTFBytes(view, 12, 'fmt ');
    view.setUint32(16, 16, true);
    view.setUint16(20, 1, true);

    view.setUint16(22, 1, true);
    view.setUint32(24, this.sampleRate, true);
    view.setUint32(28, this.sampleRate * 4, true);
    view.setUint16(32, 4, true);
    view.setUint16(34, 16, true);

    this.writeUTFBytes(view, 36, 'data');
    view.setUint32(40, interleaved.length * 2, true);

    var lng = interleaved.length;
    console.log("LNG: " + interleaved.length);
    var index = 44;
    var volume = 1;

    var sum = 0;
    var number = 0;
    var max = 0;
    var start = lng - 1;

    for (var i = 0; i < lng; i++) {
	sum += Math.abs(interleaved[i]);
	number++;
	if (Math.abs(interleaved[i]) > max) {
	    max = Math.abs(interleaved[i]);
	}
	if (start == (lng - 1) && Math.abs(interleaved[i]) >= threshold) {
	    start = i;
	}
    }

    start = Math.max(start - 50, 0);

    console.log("AVG energy: " + sum / number + ", MAX energy: " + max);
    console.log("SAVE from: " + start + " to end (cut "
	    + Math.round((100 * start) / number, 2) + "%)");

    for (var i = 0; i < lng; i++) {

	if (i >= start) {

	    var sign = (interleaved[i] < 0)

	    interleaved[i] = (0.9 / max) * interleaved[i] * interleaved[i];

	    if (sign)
		interleaved[i] *= (-1);

	    view.setInt16(index, interleaved[i] * (0x7FFF * volume), true);
	    index += 2;

	}
    }

    this.sendWave(view, "rest/?type=POST");
    console.log("Ajax should be done");

    console.log(this.lastCharacter);

}

Recorder.prototype.sendWave = function(view, url) {

    var blob = new Blob([ view ], {
	type : 'audio/wav'
    });

    var rec = this;

    var fd = new FormData();
    fd.append('test.vaw', blob);
    $.ajax({
	processData : false,
	contentType : false,
	url : url,
	context : document.body,
	data : fd,
	type : 'POST',
	async : false
    }).done(function(data) {
	console.log("Ajax done");
	rec.lastCharacter = data;
    }).error(function(xhr, status, err) {
	rec.lastCharacter = "X";
	throw "Błąd ropzoznawania głoski!";
    });

}

Recorder.prototype.interleave = function(leftChannel) {
    var length = leftChannel.length;
    console.log("LC LNG: " + length);
    var result = new Float32Array(length);

    var inputIndex = 0;

    for (var index = 0; index < length;) {
	result[index++] = leftChannel[inputIndex]
	inputIndex++;
    }
    return result;
}

Recorder.prototype.mergeBuffers = function(channelBuffer, recordingLength) {
    var result = new Float32Array(recordingLength);
    var offset = 0;
    var lng = channelBuffer.length;
    for (var i = 0; i < lng; i++) {
	var buffer = channelBuffer[i];
	result.set(buffer, offset);
	offset += buffer.length;
    }
    return result;
}

Recorder.prototype.writeUTFBytes = function(view, offset, string) {
    var lng = string.length;
    for (var i = 0; i < lng; i++) {
	view.setUint8(offset + i, string.charCodeAt(i));
    }
}

Recorder.prototype.init = function(e) {

    console.log("Initialize of recorder");
    this.audioContext = window.AudioContext || window.webkitAudioContext;
    this.context = new audioContext();

    this.volume = context.createGain();

    this.audioInput = context.createMediaStreamSource(e);

    this.audioInput.connect(volume);

    var bufferSize = 2048;
    this.recorder = this.context.createJavaScriptNode(bufferSize, 1, 2);

    this.recorder.onaudioprocess = function(e) {

	if (!rec.recording)
	    return;

	var left = e.inputBuffer.getChannelData(0);

	rec.leftchannel.push(new Float32Array(left));
	rec.recordingLength += bufferSize;
    }

    this.volume.connect(recorder);
    this.recorder.connect(context.destination);
    console.log("Recorder is ready");

}

Recorder.prototype.rewrite = function(data) {
    return data;
}